package com.xcity.game.combat.listener.combat;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Player;
import com.xcity.game.battle.pve.PVEStageDropListener;
import com.xcity.game.battle.pve.PVEUtils;
import com.xcity.game.battle.res.ResStage;
import com.xcity.game.battle.res.ResStageService;
import com.xcity.game.combat.Combat;
import com.xcity.game.combat.Combat.Type;
import com.xcity.game.combat.CombatException;
import com.xcity.game.combat.CombatService;
import com.xcity.game.combat.Round;
import com.xcity.game.combat.builder.DefaultCombatBuilder;
import com.xcity.game.combat.listener.CombatListener;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.ItemResponse;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.formation.Formation;
import com.xcity.game.item.drop.Drop;
import com.xcity.game.item.drop.impl.ItemDrop;
import com.xcity.game.npc.NpcTemplate;
import com.xcity.pomelo.push.msg.CombatEndPush;
import com.xcity.pomelo.request.CombatInfoRequest;
import com.xcity.pomelo.request.CombatResStageRequest;
import com.xcity.pomelo.response.CombatInfoResponse;
import com.xcity.pomelo.response.CombatInfoResponse.TeamBuilder;
import com.xcity.pomelo.response.CombatResponse;

import naga.x.App;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Packet;
import naga.x.net.Session;

/**
 * 资源副本战斗
 */
public class ResStageCombatListener implements CombatListener{

	protected Player player;
	protected List<Employee> employees;
	protected ResStage stage;
	protected static final Logger LOG = CombatService.LOG;
	protected long createTime;

	static class Result {
		public int id;// 关卡
//		public DropInfoV2 rewards = DropInfoV2.EMPTY;//掉落
		public RewardInfo rewards = RewardInfo.EMPTY;
		public int dayCount;//已打次数
		public int cdSecond;//资源副本 CD
		public int resType;
		public Result(Player player, ResStage stage){
			this(player, stage, null, 0f);
		}
		public Result(Player player, ResStage stage, /*List<Drop> drops*/List<PVEStageDropListener> list, float addedRatio){
			this.id = stage.getIndex();
			this.resType = stage.getTemplate().getType();
//			this.rewards = drops != null ? new DropInfoV2(drops, addedRatio) : DropInfoV2.EMPTY;
			this.rewards = list != null && list.size() > 0? new RewardInfo(list.get(0)) : RewardInfo.EMPTY;
			int type = stage.getTemplate().getType();
			this.dayCount = player.getResStages().getTodayCount(stage);
			this.cdSecond = player.getResStages().getTypeInfo().getLeftSecondByType(type);
		}
	}
	
	public static class RewardInfo{
		public int gold;
		public int exp;
		//协议是统一处理的 为了不改协议 暂时用itemdrop
		public List<ItemDrop> items = Collections.emptyList();
		public static final RewardInfo EMPTY = new RewardInfo();
		public RewardInfo() {}
		public RewardInfo(PVEStageDropListener listener) {
			gold = listener.getMoney();
			exp = listener.getExp();
			List<ItemResponse> drops = listener.getItems();
			if (drops != null && !drops.isEmpty()) {
				items = new ArrayList<ItemDrop>(drops.size());
				for(int i = 0; i < drops.size(); i++){
					ItemResponse resps = drops.get(i);
					ItemDrop drop = new ItemDrop(0, resps.getId(), resps.getCount());
					items.add(drop);
				}
			}
		}
	}
	
	@Override
	public void prepareCombat(Session session, CombatInfoRequest packet) throws CombatException {
		player = session.getClient();
		int index = packet.getResStageIndex();
		init(index);
		
		TeamBuilder playerTeamBuilder = new TeamBuilder().setLeader(player);
		for(int i = 0; i < employees.size(); i++){
			playerTeamBuilder.addMember(employees.get(i));
		}
		
		TeamBuilder npcTeamBuilder = new TeamBuilder();
		NpcTemplate npcLeader = stage.getTemplate().getBoss();
		npcTeamBuilder.setLeader(npcLeader);
		NpcTemplate[] npcs = stage.getTemplate().getNpcs();
		for(int i = 0, len = npcs.length; i < len; i++){
			npcTeamBuilder.addMember(npcs[i]);
		}
		
		Packet res = new CombatInfoResponse(packet.getSerial(), playerTeamBuilder.build(), npcTeamBuilder.build(), Formation.TYPE_NORMAL);
		session.send(res);
	}

	@Override
	public CombatResponse create(CombatService service, Type type, Session session, Packet packet) throws CombatException {
		CombatResStageRequest req = (CombatResStageRequest) packet;
		player = session.getClient();
		int index = req.getId();
		init(index);
		validate();
		
//		PVECombatBuilder builder = new PVECombatBuilder()
//				.setPlayer(player)
//				.setEmployees(employees)
//				.setBossNpc(stage.getTemplate().getBoss())
//				.setListener(this);
		DefaultCombatBuilder builder = new DefaultCombatBuilder()
				.setType(Combat.Type.RESOURCE_INSTANCE)
				.setListener(this)
				.setSourceLeader(player)
				.addSourceMembers(employees);
		NpcTemplate boss = stage.getTemplate().getBoss();
		builder.setDestLeader(boss != null ? boss.toCombatabale() : null);
		NpcTemplate[] npcs = stage.getTemplate().getNpcs();
		for(int i = 0; i < npcs.length; i++){
			NpcTemplate npc = npcs[i];
			builder.addDestMember(npc != null ? npc.toCombatabale() : null);
		}
		
		LOG.info("[RESSTAGE]ID[{}]STAGE[{}]", player.getId(), stage.getId());
		this.createTime = TimeUpdater.getInstance().now();
		return new CombatResponse(req.getSerial(), builder.build());
	}

	@Override
	public void end(Combat combat, boolean notify) {
		Result ref = null;
		long endTime = TimeUpdater.getInstance().now();
		player.getResStages().getTypeInfo().setLastFightTime(stage.getTemplate().getType(), endTime);
		CombatEndPush push = new CombatEndPush(Combat.FAIL, Combat.Type.RESOURCE_INSTANCE, combat.getId());
		if(combat.isWinner(player.getId())){
			List<Drop> drops = Collections.emptyList();
			float addedRatio = 0f;
			List<Drop> allDrops = stage.getTemplate().getRewardsDrop();
			drops = new ArrayList<Drop>(allDrops.size());
			List<PVEStageDropListener> listenerList = new ArrayList<PVEStageDropListener>();
			PVEUtils.calcPVEStageDrop(player, employees, stage.getTemplate().getNpcs(), stage.getTemplate().getBoss(), drops, allDrops, addedRatio, 1, listenerList, Cause.RES_STAGE_END);
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_RES_SUCCESS, player);
			ref = new Result(player, stage, listenerList, addedRatio);
			push.setResult(Combat.SUCC);
			push.setRef(ref);
			stage.end(endTime);
		}else{
			ref = new Result(player, stage);
			push.setRef(ref);
		}
		if (notify) {
			player.send(push);
		}
		LOG.info("[RESSTAGEEND]ID[{}]STAGE[{}]RESULT[{}]", player.getId(), stage.getId(), push.getResult());
	}
	
	public void init(int stageIndex) throws CombatException{
		List<ResStage> stages = player.getResStages().getStages();
		//等级
		if(player.getLevel() < GameStaticConfig.resStageOpenLvl){
			throw new CombatException(MessageConst.RES_STAGE_NOT_OPEN);
		}
		stage = stageIndex >= 0 && stageIndex < stages.size() ? stages.get(stageIndex) : stages.get(stageIndex = 0);
		int type = stage.getTemplate().getType();
		int limit = player.getResStages().getLevelLimitByType(type);
		if(limit > stage.getTemplate().getLevelLimit()){
			limit = stage.getTemplate().getLevelLimit();
		}
		if(player.getLevel() < limit){
			throw new CombatException(MessageFormat.format(MessageConst.RES_STAGE_LEVEL_LIMIT, limit));
		}
		//次数
		if(player.getResStages().getTodayCount(stage) >= player.getResStages().getTodayMaxCount(stage)){
			throw new CombatException(MessageConst.RES_STAGE_NO_COUNT);
		}
		//CD
		if(player.getResStages().getTypeInfo().getLeftSecondByType(type) > 0){
			throw new CombatException(MessageConst.RES_STAGE_NOT_TIMEUP);
		}
		//TODO 副本体力-
		int cost = App.getApp().getServiceManager().get(ResStageService.class).getTypeTempList().get(type).getCost();
		if(player.getVigour() < cost){
			throw new CombatException(MessageConst.VIGOUR_NOT_ENOUGH);
		}
		//上一关通关情况
		if(stage.getTemplate().getPreviousIndex() > 0){
			ResStage resStage = player.getResStages().getStageByIndex(stage.getTemplate().getPreviousIndex());
			if(resStage != null){
				if(!resStage.isPass()){
					throw new CombatException(MessageConst.RES_STAGE_NEED_PREVIOUS_PASS);
				}
				
			}
		}
//		long[] employeeIds = CombatUtils.getCombatFormation(player, true);
		employees = Arrays.asList(player.getFormations().get(Formation.TYPE_NORMAL).getUnits());//new ArrayList<Employee>(employeeIds.length);
//		for(long eid : employeeIds){
//			Employee e = eid != 0L ? player.getEmployees().get(eid) : null;
//			employees.add(e);
//		}
	}
	
	public void validate() throws CombatException{
		//等级
		if(player.getLevel() < GameStaticConfig.resStageOpenLvl){
			throw new CombatException(MessageConst.RES_STAGE_NOT_OPEN);
		}
		int type = stage.getTemplate().getType();
		if(player.getLevel() < player.getResStages().getLevelLimitByType(type)){
			throw new CombatException(MessageConst.RES_STAGE_NOT_OPEN);
		}
		if(stage.getTemplate().getLevelLimit() > player.getLevel()){
			throw new CombatException(MessageFormat.format(MessageConst.RES_STAGE_LEVEL_LIMIT, stage.getTemplate().getLevelLimit()));
		}
		//CD
		if(player.getResStages().getTypeInfo().getLeftSecondByType(type) > 0){
			throw new CombatException(MessageConst.RES_STAGE_NOT_TIMEUP);
		}
		for(int i = 0; i < employees.size(); i++){
			Employee e = employees.get(i);
			if(e != null){
				//员工体力
				com.xcity.db.entity.Employee.State state = com.xcity.db.entity.Employee.State.IN_FORMATION;
				if(state.enable && e.getState() != state){
					throw new CombatException(MessageConst.EMPLOYEE_COMBAT_STATE_ERROR);
				}
				//不处理员工精力
			}
		}
		//TODO 副本体力-
		int cost = App.getApp().getServiceManager().get(ResStageService.class).getTypeTempList().get(type).getCost();
		if(cost > 0 && player.decVigour(cost, Cause.RES_STAGE_FIGHT)){//!player.decStrength(cost, Cause.RES_STAGE_FIGHT)
		}
		//不扣除员工精力
		//扣除次数
		if(!player.getResStages().getTypeInfo().tryAddDayCount(stage.getTemplate().getType())){
			throw new CombatException(MessageConst.RES_STAGE_NO_COUNT);
		}
		
	}

	@Override
	public void roundStart(Round round) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void roundEnd(Round round) {
		// TODO Auto-generated method stub
		
	}
}
